package LunaServer.logging;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 线程安全且高性能的日志记录器
 */
public class Logger {
    // 单例实例
    private static volatile Logger instance;

    // 日志队列，用于异步处理日志
    private final BlockingQueue<LogEntry> logQueue = new LinkedBlockingQueue<>();

    // 控制日志写入线程的运行状态
    private final AtomicBoolean isRunning = new AtomicBoolean(true);

    // 日志写入线程
    private final Thread loggerThread;

    // 日志文件路径
    private final String logFilePath;

    // 监听器列表（线程安全）
    private final List<LogListener> listeners = new CopyOnWriteArrayList<>();

    // 时间格式化器
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 私有构造函数，防止外部实例化
     * 
     * @param logFilePath 日志文件路径
     */
    private Logger(String logFilePath) {
        this.logFilePath = logFilePath;
        this.loggerThread = new Thread(this::processLogs);
        this.loggerThread.setDaemon(true); // 设置为守护线程
        this.loggerThread.start();
    }

    /**
     * 获取日志记录器单例实例
     * 
     * @param logFilePath 日志文件路径
     * @return Logger实例
     */
    public static Logger getInstance(String logFilePath) {
        if (instance == null) {
            synchronized (Logger.class) {
                if (instance == null) {
                    instance = new Logger(logFilePath);
                }
            }
        }
        return instance;
    }

    /**
     * 获取日志记录器单例实例（使用默认日志文件路径）
     * 
     * @return Logger实例
     */
    public static Logger getInstance() {
        return getInstance("server.log");
    }

    /**
     * 记录INFO级别日志
     * 
     * @param message 日志消息
     */
    public void info(String message) {
        log(LogLevel.INFO, message);
    }

    /**
     * 记录WARN级别日志
     * 
     * @param message 日志消息
     */
    public void warn(String message) {
        log(LogLevel.WARN, message);
    }

    /**
     * 记录ERROR级别日志
     * 
     * @param message 日志消息
     */
    public void error(String message) {
        log(LogLevel.ERROR, message);
    }

    /**
     * 记录DEBUG级别日志
     * 
     * @param message 日志消息
     */
    public void debug(String message) {
        log(LogLevel.DEBUG, message);
    }

    /**
     * 注册日志监听器（UI 可调用以接收日志事件）
     */
    public void addListener(LogListener listener) {
        if (listener != null) {
            listeners.add(listener);
        }
    }

    /**
     * 注销日志监听器
     */
    public void removeListener(LogListener listener) {
        if (listener != null) {
            listeners.remove(listener);
        }
    }

    /**
     * 记录日志的核心方法
     * 
     * @param level   日志级别
     * @param message 日志消息
     */
    private void log(LogLevel level, String message) {
        if (!isRunning.get()) {
            // 如果日志系统已关闭，则直接输出到控制台
            System.out.println(
                    LocalDateTime.now().format(TIME_FORMATTER) + " [" + level.name() + "] " + message);
            return;
        }

        // 如果日志系统启动
        try {
            // 创建一个日志条目
            LogEntry entry = new LogEntry(level, message, LocalDateTime.now());
            // 将日志条目放入队列，不阻塞
            logQueue.offer(entry);
        } catch (Exception e) {
            // 如果队列满了或者其他异常，直接输出到控制台
            System.err.println("Failed to queue log entry: " + e.getMessage());
            System.out.println(
                    LocalDateTime.now().format(TIME_FORMATTER) + " [" + level.name() + "] " + message);
        }
    }

    /**
     * 异步处理日志的后台线程方法
     */
    private void processLogs() {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(logFilePath, true))) {
            while (isRunning.get() || !logQueue.isEmpty()) {
                LogEntry entry = logQueue.poll(); // 非阻塞获取

                if (entry != null) {
                    String logLine = entry.timestamp.format(TIME_FORMATTER) +
                            " [" + entry.level + "] " +
                            entry.message + System.lineSeparator();

                    // 通知监听器（在写入文件之前）
                    for (LogListener l : listeners) {
                        try {
                            l.onLog(entry.level, entry.message, entry.timestamp);
                        } catch (Exception ignore) {
                            // 保持日志系统稳定
                        }
                    }

                    writer.write(logLine);
                    writer.flush(); // 确保立即写入磁盘
                } else {
                    // 如果队列为空，短暂休眠以减少CPU占用
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        } catch (IOException e) {
            System.err.println("Error writing to log file: " + e.getMessage());
        }
    }

    /**
     * 关闭日志记录器
     */
    public void shutdown() {
        isRunning.set(false);
        try {
            loggerThread.join(5000); // 等待最多5秒让日志线程完成
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * 内部类，表示一个日志条目
     */
    private static class LogEntry {
        final LogLevel level;
        final String message;
        final LocalDateTime timestamp;

        LogEntry(LogLevel level, String message, LocalDateTime timestamp) {
            this.level = level;
            this.message = message;
            this.timestamp = timestamp;
        }
    }
}